//
// System.Web.UI.WebControls.DetailsView.cs
//
// Authors:
//	Lluis Sanchez Gual (lluis@novell.com)
//
// (C) 2005-2010 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
// 
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//

using System;
using System.Collections;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Web.UI;
using System.Security.Permissions;
using System.Text;
using System.IO;
using System.Reflection;

namespace System.Web.UI.WebControls
{
	[SupportsEventValidation]
	[ToolboxDataAttribute ("<{0}:DetailsView runat=\"server\" Width=\"125px\" Height=\"50px\"></{0}:DetailsView>")]
	[DesignerAttribute ("System.Web.UI.Design.WebControls.DetailsViewDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
	[ControlValuePropertyAttribute ("SelectedValue")]
	[DefaultEventAttribute ("PageIndexChanging")]
	[DataKeyProperty ("DataKey")]
	[AspNetHostingPermissionAttribute (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
	[AspNetHostingPermissionAttribute (SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
	public class DetailsView: CompositeDataBoundControl, ICallbackEventHandler, ICallbackContainer, IDataItemContainer, INamingContainer, IPostBackEventHandler, IPostBackContainer
		, IDataBoundItemControl, IDataBoundControl, IFieldControl
	{
		object dataItem;
		
		Table table;
		DetailsViewRowCollection rows;
		DetailsViewRow headerRow;
		DetailsViewRow footerRow;
		DetailsViewRow bottomPagerRow;
		DetailsViewRow topPagerRow;
		
		IOrderedDictionary currentEditRowKeys;
		IOrderedDictionary currentEditNewValues;
		IOrderedDictionary currentEditOldValues;
		
		ITemplate pagerTemplate;
		ITemplate emptyDataTemplate;
		ITemplate headerTemplate;
		ITemplate footerTemplate;
		
		PropertyDescriptor[] cachedKeyProperties;
		readonly string[] emptyKeys = new string[0];
		readonly string unhandledEventExceptionMessage = "The DetailsView '{0}' fired event {1} which wasn't handled.";
		
		// View state
		DataControlFieldCollection columns;
		PagerSettings pagerSettings;
		
		TableItemStyle alternatingRowStyle;
		TableItemStyle editRowStyle;
		TableItemStyle insertRowStyle;
		TableItemStyle emptyDataRowStyle;
		TableItemStyle footerStyle;
		TableItemStyle headerStyle;
		TableItemStyle pagerStyle;
		TableItemStyle rowStyle;
		TableItemStyle commandRowStyle;
		TableItemStyle fieldHeaderStyle;
		
		IOrderedDictionary _keyTable;
		DataKey key;
		DataKey oldEditValues;
		AutoGeneratedFieldProperties[] autoFieldProperties;
		
		static readonly object PageIndexChangedEvent = new object();
		static readonly object PageIndexChangingEvent = new object();
		static readonly object ItemCommandEvent = new object();
		static readonly object ItemCreatedEvent = new object();
		static readonly object ItemDeletedEvent = new object();
		static readonly object ItemDeletingEvent = new object();
		static readonly object ItemInsertedEvent = new object();
		static readonly object ItemInsertingEvent = new object();
		static readonly object ModeChangingEvent = new object();
		static readonly object ModeChangedEvent = new object();
		static readonly object ItemUpdatedEvent = new object();
		static readonly object ItemUpdatingEvent = new object();
		
		// Control state
		int pageIndex;
		DetailsViewMode currentMode = DetailsViewMode.ReadOnly; 
		bool hasCurrentMode;
		int pageCount;
		
		public DetailsView ()
		{
			rows = new DetailsViewRowCollection (new ArrayList ());
		}
		
		public event EventHandler PageIndexChanged {
			add { Events.AddHandler (PageIndexChangedEvent, value); }
			remove { Events.RemoveHandler (PageIndexChangedEvent, value); }
		}
		
		public event DetailsViewPageEventHandler PageIndexChanging {
			add { Events.AddHandler (PageIndexChangingEvent, value); }
			remove { Events.RemoveHandler (PageIndexChangingEvent, value); }
		}
		
		public event DetailsViewCommandEventHandler ItemCommand {
			add { Events.AddHandler (ItemCommandEvent, value); }
			remove { Events.RemoveHandler (ItemCommandEvent, value); }
		}
		
		public event EventHandler ItemCreated {
			add { Events.AddHandler (ItemCreatedEvent, value); }
			remove { Events.RemoveHandler (ItemCreatedEvent, value); }
		}
		
		public event DetailsViewDeletedEventHandler ItemDeleted {
			add { Events.AddHandler (ItemDeletedEvent, value); }
			remove { Events.RemoveHandler (ItemDeletedEvent, value); }
		}
		
		public event DetailsViewDeleteEventHandler ItemDeleting {
			add { Events.AddHandler (ItemDeletingEvent, value); }
			remove { Events.RemoveHandler (ItemDeletingEvent, value); }
		}
		
		public event DetailsViewInsertedEventHandler ItemInserted {
			add { Events.AddHandler (ItemInsertedEvent, value); }
			remove { Events.RemoveHandler (ItemInsertedEvent, value); }
		}
		
		public event DetailsViewInsertEventHandler ItemInserting {
			add { Events.AddHandler (ItemInsertingEvent, value); }
			remove { Events.RemoveHandler (ItemInsertingEvent, value); }
		}
		
		public event DetailsViewModeEventHandler ModeChanging {
			add { Events.AddHandler (ModeChangingEvent, value); }
			remove { Events.RemoveHandler (ModeChangingEvent, value); }
		}
		
		public event EventHandler ModeChanged {
			add { Events.AddHandler (ModeChangedEvent, value); }
			remove { Events.RemoveHandler (ModeChangedEvent, value); }
		}
		
		public event DetailsViewUpdatedEventHandler ItemUpdated {
			add { Events.AddHandler (ItemUpdatedEvent, value); }
			remove { Events.RemoveHandler (ItemUpdatedEvent, value); }
		}
		
		public event DetailsViewUpdateEventHandler ItemUpdating {
			add { Events.AddHandler (ItemUpdatingEvent, value); }
			remove { Events.RemoveHandler (ItemUpdatingEvent, value); }
		}
		
		protected virtual void OnPageIndexChanged (EventArgs e)
		{
			if (Events != null) {
				EventHandler eh = (EventHandler) Events [PageIndexChangedEvent];
				if (eh != null) eh (this, e);
			}
		}
		
		protected virtual void OnPageIndexChanging (DetailsViewPageEventArgs e)
		{
			if (Events != null) {
				DetailsViewPageEventHandler eh = (DetailsViewPageEventHandler) Events [PageIndexChangingEvent];
				if (eh != null) {
					eh (this, e);
					return;
				}
			}
			if (!IsBoundUsingDataSourceID)
				throw new HttpException (String.Format (unhandledEventExceptionMessage, ID, "PageIndexChanging"));
		}
		
		protected virtual void OnItemCommand (DetailsViewCommandEventArgs e)
		{
			if (Events != null) {
				DetailsViewCommandEventHandler eh = (DetailsViewCommandEventHandler) Events [ItemCommandEvent];
				if (eh != null) eh (this, e);
			}
		}
		
		protected virtual void OnItemCreated (EventArgs e)
		{
			if (Events != null) {
				EventHandler eh = (EventHandler) Events [ItemCreatedEvent];
				if (eh != null) eh (this, e);
			}
		}
		
		protected virtual void OnItemDeleted (DetailsViewDeletedEventArgs e)
		{
			if (Events != null) {
				DetailsViewDeletedEventHandler eh = (DetailsViewDeletedEventHandler) Events [ItemDeletedEvent];
				if (eh != null) eh (this, e);
			}
		}
		
		protected virtual void OnItemInserted (DetailsViewInsertedEventArgs e)
		{
			if (Events != null) {
				DetailsViewInsertedEventHandler eh = (DetailsViewInsertedEventHandler) Events [ItemInsertedEvent];
				if (eh != null) eh (this, e);
			}
		}
		
		protected virtual void OnItemInserting (DetailsViewInsertEventArgs e)
		{
			if (Events != null) {
				DetailsViewInsertEventHandler eh = (DetailsViewInsertEventHandler) Events [ItemInsertingEvent];
				if (eh != null) {
					eh (this, e);
					return;
				}
			}
			if (!IsBoundUsingDataSourceID)
				throw new HttpException (String.Format (unhandledEventExceptionMessage, ID, "ItemInserting"));
		}
		
		protected virtual void OnItemDeleting (DetailsViewDeleteEventArgs e)
		{
			if (Events != null) {
				DetailsViewDeleteEventHandler eh = (DetailsViewDeleteEventHandler) Events [ItemDeletingEvent];
				if (eh != null) {
					eh (this, e);
					return;
				}
			}
			if (!IsBoundUsingDataSourceID)
				throw new HttpException (String.Format (unhandledEventExceptionMessage, ID, "ItemDeleting"));
		}
		
		protected virtual void OnModeChanged (EventArgs e)
		{
			if (Events != null) {
				EventHandler eh = (EventHandler) Events [ModeChangedEvent];
				if (eh != null) eh (this, e);
			}
		}
		
		protected virtual void OnModeChanging (DetailsViewModeEventArgs e)
		{
			if (Events != null) {
				DetailsViewModeEventHandler eh = (DetailsViewModeEventHandler) Events [ModeChangingEvent];
				if (eh != null) {
					eh (this, e);
					return;
				}
			}
			if (!IsBoundUsingDataSourceID)
				throw new HttpException (String.Format (unhandledEventExceptionMessage, ID, "ModeChanging"));
		}
		
		protected virtual void OnItemUpdated (DetailsViewUpdatedEventArgs e)
		{
			if (Events != null) {
				DetailsViewUpdatedEventHandler eh = (DetailsViewUpdatedEventHandler) Events [ItemUpdatedEvent];
				if (eh != null) eh (this, e);
			}
		}
		
		protected virtual void OnItemUpdating (DetailsViewUpdateEventArgs e)
		{
			if (Events != null) {
				DetailsViewUpdateEventHandler eh = (DetailsViewUpdateEventHandler) Events [ItemUpdatingEvent];
				if (eh != null) {
					eh (this, e);
					return;
				}
			}
			if (!IsBoundUsingDataSourceID)
				throw new HttpException (String.Format (unhandledEventExceptionMessage, ID, "ItemUpdating"));
		}
		
		DataBoundControlMode IDataBoundItemControl.Mode {
			get {
				switch (CurrentMode) {
					case DetailsViewMode.ReadOnly:
						return DataBoundControlMode.ReadOnly;

					case DetailsViewMode.Edit:
						return DataBoundControlMode.Edit;

					case DetailsViewMode.Insert:
						return DataBoundControlMode.Insert;

					default:
						throw new InvalidOperationException (String.Format ("Unsupported CurrentMode value '{0}'", CurrentMode));
				}
			}
		}

		IDataSource IDataBoundControl.DataSourceObject {
			get { return base.DataSourceObject; }
		}

		IAutoFieldGenerator IFieldControl.FieldsGenerator {
			get {
				throw new NotImplementedException ();
			}
			
			set {
				throw new NotImplementedException ();
			}
		}
		[WebCategoryAttribute ("Paging")]
		[DefaultValueAttribute (false)]
		public virtual bool AllowPaging {
			get {
				object ob = ViewState ["AllowPaging"];
				if (ob != null)
					return (bool) ob;
				return false;
			}
			set {
				ViewState ["AllowPaging"] = value;
				RequireBinding ();
			}
		}
		
		[DefaultValueAttribute (null)]
		[WebCategoryAttribute ("Styles")]
		[PersistenceMode (PersistenceMode.InnerProperty)]
		[NotifyParentProperty (true)]
		[DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
		public TableItemStyle AlternatingRowStyle {
			get {
				if (alternatingRowStyle == null) {
					alternatingRowStyle = new TableItemStyle ();
					if (IsTrackingViewState)
						alternatingRowStyle.TrackViewState();
				}
				return alternatingRowStyle;
			}
		}

		[WebCategoryAttribute ("Behavior")]
		[DefaultValueAttribute (false)]
		public virtual bool AutoGenerateEditButton {
			get {
				object ob = ViewState ["AutoGenerateEditButton"];
				if (ob != null)
					return (bool) ob;
				return false;
			}
			set {
				ViewState ["AutoGenerateEditButton"] = value;
				RequireBinding ();
			}
		}

		[WebCategoryAttribute ("Behavior")]
		[DefaultValueAttribute (false)]
		public virtual bool AutoGenerateDeleteButton {
			get {
				object ob = ViewState ["AutoGenerateDeleteButton"];
				if (ob != null)
					return (bool) ob;
				return false;
			}
			set {
				ViewState ["AutoGenerateDeleteButton"] = value;
				RequireBinding ();
			}
		}

		[WebCategoryAttribute ("Behavior")]
		[DefaultValueAttribute (false)]
		public virtual bool AutoGenerateInsertButton {
			get {
				object ob = ViewState ["AutoGenerateInsertButton"];
				if (ob != null)
					return (bool) ob;
				return false;
			}
			set {
				ViewState ["AutoGenerateInsertButton"] = value;
				RequireBinding ();
			}
		}

		[WebCategoryAttribute ("Behavior")]
		[DefaultValueAttribute (true)]
		public virtual bool AutoGenerateRows {
			get {
				object ob = ViewState ["AutoGenerateRows"];
				if (ob != null)
					return (bool) ob;
				return true;
			}
			set {
				ViewState ["AutoGenerateRows"] = value;
				RequireBinding ();
			}
		}
		
		[UrlPropertyAttribute]
		[WebCategoryAttribute ("Appearance")]
		[DefaultValueAttribute ("")]
		[EditorAttribute ("System.Web.UI.Design.ImageUrlEditor, " + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
		public virtual string BackImageUrl {
			get {
				if (ControlStyleCreated)
					return ((TableStyle) ControlStyle).BackImageUrl;
				return String.Empty;
			}
			set {
				((TableStyle) ControlStyle).BackImageUrl = value;
			}
		}

		[DesignerSerializationVisibilityAttribute (DesignerSerializationVisibility.Hidden)]
		[BrowsableAttribute (false)]
		public virtual DetailsViewRow BottomPagerRow {
			get {
				EnsureChildControls ();
				return bottomPagerRow;
			}
		}
	
		[WebCategoryAttribute ("Accessibility")]
		[DefaultValueAttribute ("")]
		[LocalizableAttribute (true)]
		public virtual string Caption {
			get {
				object ob = ViewState ["Caption"];
				if (ob != null)
					return (string) ob;
				return String.Empty;
			}
			set {
				ViewState ["Caption"] = value;
				RequireBinding ();
			}
		}
		
		[WebCategoryAttribute ("Accessibility")]
		[DefaultValueAttribute (TableCaptionAlign.NotSet)]
		public virtual TableCaptionAlign CaptionAlign {
			get {
				object o = ViewState ["CaptionAlign"];
				if(o != null)
					return (TableCaptionAlign) o;
				return TableCaptionAlign.NotSet;
			}
			set {
				ViewState ["CaptionAlign"] = value;
				RequireBinding ();
			}
		}

		[WebCategoryAttribute ("Layout")]
		[DefaultValueAttribute (-1)]
		public virtual int CellPadding {
			get {
				if (ControlStyleCreated)
					return ((TableStyle) ControlStyle).CellPadding;
				return -1;
			}
			set { ((TableStyle) ControlStyle).CellPadding = value; }
		}

		[WebCategoryAttribute ("Layout")]
		[DefaultValueAttribute (0)]
		public virtual int CellSpacing {
			get {
				if (ControlStyleCreated)
					return ((TableStyle) ControlStyle).CellSpacing;
				return 0;
			}
			set { ((TableStyle) ControlStyle).CellSpacing = value; }
		}
		
		[DefaultValueAttribute (null)]
		[WebCategoryAttribute ("Styles")]
		[PersistenceMode (PersistenceMode.InnerProperty)]
		[NotifyParentProperty (true)]
		[DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
		public TableItemStyle CommandRowStyle {
			get {
				if (commandRowStyle == null) {
					commandRowStyle = new TableItemStyle ();
					if (IsTrackingViewState)
						commandRowStyle.TrackViewState();
				}
				return commandRowStyle;
			}
		}

		[DesignerSerializationVisibilityAttribute (DesignerSerializationVisibility.Hidden)]
		[BrowsableAttribute (false)]
		public DetailsViewMode CurrentMode {
			get { return hasCurrentMode ? currentMode : DefaultMode; }

			private set {
				hasCurrentMode = true;
				currentMode = value;
			}
		}

		DetailsViewMode defaultMode = DetailsViewMode.ReadOnly;
		[DefaultValueAttribute (DetailsViewMode.ReadOnly)]
		[WebCategoryAttribute ("Behavior")]
		public virtual DetailsViewMode DefaultMode {
			get { return defaultMode; }
			set {
				defaultMode = value;
				RequireBinding ();
			}
		}
	
		[EditorAttribute ("System.Web.UI.Design.WebControls.DataControlFieldTypeEditor, " + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
		[MergablePropertyAttribute (false)]
		[PersistenceModeAttribute (PersistenceMode.InnerProperty)]
		[DefaultValueAttribute (null)]
		[WebCategoryAttribute ("Misc")]
		public virtual DataControlFieldCollection Fields {
			get {
				if (columns == null) {
					columns = new DataControlFieldCollection ();
					columns.FieldsChanged += new EventHandler (OnFieldsChanged);
					if (IsTrackingViewState)
						((IStateManager)columns).TrackViewState ();
				}
				return columns;
			}
		}

		string[] dataKeyNames = null;

		[DefaultValueAttribute (null)]
		[WebCategoryAttribute ("Data")]
		[TypeConverter (typeof(StringArrayConverter))]
		[EditorAttribute ("System.Web.UI.Design.WebControls.DataFieldEditor, " + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
		public virtual string[] DataKeyNames {
			get {
				if (dataKeyNames == null)
					return emptyKeys;
				else
					return dataKeyNames;
			}
			set {
				dataKeyNames = value;
				RequireBinding ();
			}
		}
		
		IOrderedDictionary KeyTable {
			get {
				if (_keyTable == null)
					_keyTable = new OrderedDictionary (DataKeyNames.Length);
				return _keyTable;
			}
		}

		[BrowsableAttribute (false)]
		[DesignerSerializationVisibilityAttribute (DesignerSerializationVisibility.Hidden)]
		public virtual DataKey DataKey {
			get {
				if (key == null)
					key = new DataKey (KeyTable);
				return key;
			}
		}

		DataKey OldEditValues {
			get {
				if (oldEditValues == null)
					oldEditValues = new DataKey (new OrderedDictionary ());
				return oldEditValues;
			}
		}

		[WebCategoryAttribute ("Styles")]
		[PersistenceMode (PersistenceMode.InnerProperty)]
		[NotifyParentProperty (true)]
		[DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
		[DefaultValueAttribute (null)]
		public TableItemStyle EditRowStyle {
			get {
				if (editRowStyle == null) {
					editRowStyle = new TableItemStyle ();
					if (IsTrackingViewState)
						editRowStyle.TrackViewState();
				}
				return editRowStyle;
			}
		}
		
		[WebCategoryAttribute ("Styles")]
		[PersistenceMode (PersistenceMode.InnerProperty)]
		[NotifyParentProperty (true)]
		[DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
		[DefaultValueAttribute (null)]
		public TableItemStyle EmptyDataRowStyle {
			get {
				if (emptyDataRowStyle == null) {
					emptyDataRowStyle = new TableItemStyle ();
					if (IsTrackingViewState)
						emptyDataRowStyle.TrackViewState();
				}
				return emptyDataRowStyle;
			}
		}
		
		[DefaultValue (null)]
		[TemplateContainer (typeof(DetailsView), BindingDirection.OneWay)]
		[PersistenceMode (PersistenceMode.InnerProperty)]
		[Browsable (false)]
		public virtual ITemplate EmptyDataTemplate {
			get { return emptyDataTemplate; }
			set { emptyDataTemplate = value; }
		}
		
		[LocalizableAttribute (true)]
		[WebCategoryAttribute ("Appearance")]
		[DefaultValueAttribute ("")]
		public virtual string EmptyDataText {
			get {
				object ob = ViewState ["EmptyDataText"];
				if (ob != null)
					return (string) ob;
				return String.Empty;
			}
			set {
				ViewState ["EmptyDataText"] = value;
				RequireBinding ();
			}
		}
	
		[WebCategoryAttribute ("Behavior")]
		[DefaultValueAttribute (false)]
		public virtual bool EnablePagingCallbacks {
			get {
				object ob = ViewState ["EnablePagingCallbacks"];
				if (ob != null)
					return (bool) ob;
				return false;
			}
			set {
				ViewState ["EnablePagingCallbacks"] = value;
				RequireBinding ();
			}
		}
	
		[WebCategoryAttribute ("Styles")]
		[PersistenceMode (PersistenceMode.InnerProperty)]
		[NotifyParentProperty (true)]
		[DefaultValue (null)]
		[DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
		public TableItemStyle FieldHeaderStyle {
			get {
				if (fieldHeaderStyle == null) {
					fieldHeaderStyle = new TableItemStyle ();
					if (IsTrackingViewState)
						fieldHeaderStyle.TrackViewState();
				}
				return fieldHeaderStyle;
			}
		}
		
		[DesignerSerializationVisibilityAttribute (DesignerSerializationVisibility.Hidden)]
		[BrowsableAttribute (false)]
		public virtual DetailsViewRow FooterRow {
			get {
				EnsureChildControls ();
				return footerRow;
			}
		}
	
		[DefaultValue (null)]
		[TemplateContainer (typeof(DetailsView), BindingDirection.OneWay)]
		[PersistenceMode (PersistenceMode.InnerProperty)]
		[Browsable (false)]
		public virtual ITemplate FooterTemplate {
			get { return footerTemplate; }
			set { footerTemplate = value; }
		}

		[LocalizableAttribute (true)]
		[WebCategoryAttribute ("Appearance")]
		[DefaultValueAttribute ("")]
		public virtual string FooterText {
			get {
				object ob = ViewState ["FooterText"];
				if (ob != null)
					return (string) ob;
				return String.Empty;
			}
			set {
				ViewState ["FooterText"] = value;
				RequireBinding ();
			}
		}
		
		[WebCategoryAttribute ("Styles")]
		[PersistenceMode (PersistenceMode.InnerProperty)]
		[NotifyParentProperty (true)]
		[DefaultValue (null)]
		[DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
		public TableItemStyle FooterStyle {
			get {
				if (footerStyle == null) {
					footerStyle = new TableItemStyle ();
					if (IsTrackingViewState)
						footerStyle.TrackViewState();
				}
				return footerStyle;
			}
		}
		
		[WebCategoryAttribute ("Appearance")]
		[DefaultValueAttribute (GridLines.Both)]
		public virtual GridLines GridLines {
			get {
				if (ControlStyleCreated)
					return ((TableStyle) ControlStyle).GridLines;
				return GridLines.Both;
			}
			set { ((TableStyle) ControlStyle).GridLines = value; }
		}

		[DesignerSerializationVisibilityAttribute (DesignerSerializationVisibility.Hidden)]
		[BrowsableAttribute (false)]
		public virtual DetailsViewRow HeaderRow {
			get {
				EnsureChildControls ();
				return headerRow;
			}
		}
	
		[WebCategoryAttribute ("Styles")]
		[PersistenceMode (PersistenceMode.InnerProperty)]
		[NotifyParentProperty (true)]
		[DefaultValue (null)]
		[DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
		public TableItemStyle HeaderStyle {
			get {
				if (headerStyle == null) {
					headerStyle = new TableItemStyle ();
					if (IsTrackingViewState)
						headerStyle.TrackViewState();
				}
				return headerStyle;
			}
		}
		
		[DefaultValue (null)]
		[TemplateContainer (typeof(DetailsView), BindingDirection.OneWay)]
		[PersistenceMode (PersistenceMode.InnerProperty)]
		[Browsable (false)]
		public virtual ITemplate HeaderTemplate {
			get { return headerTemplate; }
			set { headerTemplate = value; }
		}

		[LocalizableAttribute (true)]
		[WebCategoryAttribute ("Appearance")]
		[DefaultValueAttribute ("")]
		public virtual string HeaderText {
			get {
				object ob = ViewState ["HeaderText"];
				if (ob != null)
					return (string) ob;
				return String.Empty;
			}
			set {
				ViewState ["HeaderText"] = value;
				RequireBinding ();
			}
		}
		
		[Category ("Layout")]
		[DefaultValueAttribute (HorizontalAlign.NotSet)]
		public virtual HorizontalAlign HorizontalAlign {
			get {
				if (ControlStyleCreated)
					return ((TableStyle) ControlStyle).HorizontalAlign;
				return HorizontalAlign.NotSet;
			}
			set { ((TableStyle) ControlStyle).HorizontalAlign = value; }
		}

		[WebCategoryAttribute ("Styles")]
		[PersistenceMode (PersistenceMode.InnerProperty)]
		[NotifyParentProperty (true)]
		[DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
		[DefaultValueAttribute (null)]
		public TableItemStyle InsertRowStyle {
			get {
				if (insertRowStyle == null) {
					insertRowStyle = new TableItemStyle ();
					if (IsTrackingViewState)
						insertRowStyle.TrackViewState();
				}
				return insertRowStyle;
			}
		}
		
		[BrowsableAttribute (false)]
		[DesignerSerializationVisibilityAttribute (DesignerSerializationVisibility.Hidden)]
		public virtual int PageCount {
			get { return pageCount; }
			private set { pageCount = value; }
		}

		[WebCategoryAttribute ("Paging")]
		[BindableAttribute (true, BindingDirection.OneWay)]
		[DefaultValueAttribute (0)]
		public virtual int PageIndex {
			get {
				if (CurrentMode == DetailsViewMode.Insert)
					return -1;
				return pageIndex;
			}
			set {
				if (value < -1)
					throw new ArgumentOutOfRangeException ("PageIndex must be non-negative");
				if (pageIndex == value || value == -1)
					return;
				pageIndex = value;
				RequireBinding ();
			}
		}
	
		[WebCategoryAttribute ("Paging")]
		[DesignerSerializationVisibilityAttribute (DesignerSerializationVisibility.Content)]
		[NotifyParentPropertyAttribute (true)]
		[PersistenceModeAttribute (PersistenceMode.InnerProperty)]
		public virtual PagerSettings PagerSettings {
			get {
				if (pagerSettings == null) {
					pagerSettings = new PagerSettings (this);
					if (IsTrackingViewState)
						((IStateManager)pagerSettings).TrackViewState ();
				}
				return pagerSettings;
			}
		}
	
		[WebCategoryAttribute ("Styles")]
		[PersistenceMode (PersistenceMode.InnerProperty)]
		[NotifyParentProperty (true)]
		[DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
		public TableItemStyle PagerStyle {
			get {
				if (pagerStyle == null) {
					pagerStyle = new TableItemStyle ();
					if (IsTrackingViewState)
						pagerStyle.TrackViewState();
				}
				return pagerStyle;
			}
		}
		
		
		[DefaultValue (null)]
		[TemplateContainer (typeof (DetailsView), BindingDirection.OneWay)]
		[PersistenceMode (PersistenceMode.InnerProperty)]
		[Browsable (false)]
		public virtual ITemplate PagerTemplate {
			get { return pagerTemplate; }
			set { pagerTemplate = value; }
		}
		
		[DesignerSerializationVisibilityAttribute (DesignerSerializationVisibility.Hidden)]
		[BrowsableAttribute (false)]
		public virtual DetailsViewRowCollection Rows {
			get {
				EnsureChildControls ();
				return rows;
			}
		}

		[BrowsableAttribute(false)]
		[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
		public IAutoFieldGenerator RowsGenerator {
			get;
			set;
		}

		[WebCategoryAttribute ("Styles")]
		[PersistenceMode (PersistenceMode.InnerProperty)]
		[NotifyParentProperty (true)]
		[DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
		[DefaultValue (null)]
		public TableItemStyle RowStyle {
			get {
				if (rowStyle == null) {
					rowStyle = new TableItemStyle ();
					if (IsTrackingViewState)
						rowStyle.TrackViewState();
				}
				return rowStyle;
			}
		}

		[DesignerSerializationVisibilityAttribute (DesignerSerializationVisibility.Hidden)]
		[BrowsableAttribute (false)]
		public object SelectedValue {
			get { return DataKey.Value; }
		}
		
		[DesignerSerializationVisibilityAttribute (DesignerSerializationVisibility.Hidden)]
		[BrowsableAttribute (false)]
		public virtual DetailsViewRow TopPagerRow {
			get {
				EnsureChildControls ();
				return topPagerRow;
			}
		}
	
		[DesignerSerializationVisibilityAttribute (DesignerSerializationVisibility.Hidden)]
		[BrowsableAttribute (false)]
		public virtual object DataItem {
			get {
				return dataItem;
			}
		}
		
		[DesignerSerializationVisibilityAttribute (DesignerSerializationVisibility.Hidden)]
		[BrowsableAttribute (false)]
		public int DataItemCount {
			get { return PageCount; }
		}		
	
		[DesignerSerializationVisibilityAttribute (DesignerSerializationVisibility.Hidden)]
		[BrowsableAttribute (false)]
		public virtual int DataItemIndex {
			get { return PageIndex; }
		}		
	
		int IDataItemContainer.DisplayIndex {
			get { return PageIndex; }
		}

		int IDataItemContainer.DataItemIndex {
			get { return DataItemIndex; }
		}

		[MonoTODO ("Make use of it in the code")]
		[DefaultValue (true)]
		public virtual bool EnableModelValidation {
			get;
			set;
		}

		public virtual bool IsBindableType (Type type)
		{
			return type.IsPrimitive || type == typeof (string) || type == typeof (DateTime) || type == typeof (Guid) || type == typeof (Decimal);
		}
		
		protected override DataSourceSelectArguments CreateDataSourceSelectArguments ()
		{
			DataSourceSelectArguments arg = new DataSourceSelectArguments ();
			DataSourceView view = GetData ();
			if (AllowPaging && view.CanPage) {
				arg.StartRowIndex = PageIndex;
				if (view.CanRetrieveTotalRowCount) {
					arg.RetrieveTotalRowCount = true;
					arg.MaximumRows = 1;
				} else
					arg.MaximumRows = -1;
			}
			return arg;
		}
		
		protected virtual ICollection CreateFieldSet (object dataItem, bool useDataSource)
		{
			bool autoGenerate = AutoGenerateRows;
			
			if (autoGenerate) {
				IAutoFieldGenerator fieldGenerator = RowsGenerator;
				if (fieldGenerator != null)
					return fieldGenerator.GenerateFields (this);
			}
			
			ArrayList fields = new ArrayList ();
			
			if (AutoGenerateRows) {
				if (useDataSource) {
					if (dataItem != null)
						fields.AddRange (CreateAutoGeneratedRows (dataItem));
				} else {
					if (autoFieldProperties != null) {
						foreach (AutoGeneratedFieldProperties props in autoFieldProperties)
							fields.Add (CreateAutoGeneratedRow (props));
					}
				}
			}
			
			fields.AddRange (Fields);
			
			if (AutoGenerateEditButton || AutoGenerateDeleteButton || AutoGenerateInsertButton) {
				CommandField field = new CommandField ();
				field.ShowEditButton = AutoGenerateEditButton;
				field.ShowDeleteButton = AutoGenerateDeleteButton;
				field.ShowInsertButton = AutoGenerateInsertButton;
				fields.Add (field);
			}
			
			return fields;
		}
		
		protected virtual ICollection CreateAutoGeneratedRows (object dataItem)
		{
			if (dataItem == null)
				return null;

			ArrayList list = new ArrayList ();
			autoFieldProperties = CreateAutoFieldProperties (dataItem);
			foreach (AutoGeneratedFieldProperties props in autoFieldProperties)
				list.Add (CreateAutoGeneratedRow (props));
			return list;
		}
		
		protected virtual AutoGeneratedField CreateAutoGeneratedRow (AutoGeneratedFieldProperties fieldProperties)
		{
			return new AutoGeneratedField (fieldProperties);
		}
		
		AutoGeneratedFieldProperties[] CreateAutoFieldProperties (object dataItem)
		{
			if (IsBindableType (dataItem.GetType ())) {
				AutoGeneratedFieldProperties field = new AutoGeneratedFieldProperties ();
				((IStateManager) field).TrackViewState ();
				field.Name = "Item";
				field.DataField = BoundField.ThisExpression;
				field.Type = dataItem.GetType ();
				return new AutoGeneratedFieldProperties [] { field };
			}

			PropertyDescriptorCollection props = TypeDescriptor.GetProperties (dataItem, false);

			if (props != null && props.Count > 0) {
				ArrayList retVal = new ArrayList ();
				foreach (PropertyDescriptor current in props) {
					if (IsBindableType (current.PropertyType)) {
						AutoGeneratedFieldProperties field = new AutoGeneratedFieldProperties ();
						((IStateManager) field).TrackViewState ();
						field.Name = current.Name;
						field.DataField = current.Name;
						for (int i = 0; i < DataKeyNames.Length; i++) {
							if (string.Compare (DataKeyNames [i], current.Name, StringComparison.InvariantCultureIgnoreCase) == 0) {
								field.IsReadOnly = true;
								break;
							}
						}
						field.Type = current.PropertyType;
						retVal.Add (field);
					}
				}
				if (retVal.Count > 0)
					return (AutoGeneratedFieldProperties []) retVal.ToArray (typeof (AutoGeneratedFieldProperties));
			}
			throw new HttpException (String.Format ("DetailsView with id '{0}' did not have any properties or attributes from which to generate fields.  Ensure that your data source has content.", ID));
		}
		
		protected virtual DetailsViewRow CreateRow (int rowIndex, DataControlRowType rowType, DataControlRowState rowState)
		{
			DetailsViewRow row;
			if (rowType == DataControlRowType.Pager)
				row = new DetailsViewPagerRow (rowIndex, rowType, rowState);
			else
				row = new DetailsViewRow (rowIndex, rowType, rowState);
			return row;
		}
		
		void RequireBinding ()
		{
			if (Initialized)
				RequiresDataBinding = true;
		}
		
		protected virtual Table CreateTable ()
		{
			return new ContainedTable (this);
		}

		protected override Style CreateControlStyle ()
		{
			TableStyle style = new TableStyle ();
			style.GridLines = GridLines.Both;
			style.CellSpacing = 0;
			return style;
		}
		
		protected override int CreateChildControls (IEnumerable dataSource, bool dataBinding)
		{
			PagedDataSource pagedDataSource = new PagedDataSource ();
			pagedDataSource.DataSource = CurrentMode != DetailsViewMode.Insert ? dataSource : null;
			pagedDataSource.AllowPaging = AllowPaging;
			pagedDataSource.PageSize = 1;
			pagedDataSource.CurrentPageIndex = PageIndex;

			if (dataBinding && CurrentMode != DetailsViewMode.Insert) {
				DataSourceView view = GetData ();
				if (view != null && view.CanPage) {
					pagedDataSource.AllowServerPaging = true;
					if (SelectArguments.RetrieveTotalRowCount)
						pagedDataSource.VirtualCount = SelectArguments.TotalRowCount;
				}
			}

			bool showPager = AllowPaging && (pagedDataSource.PageCount > 1);

			Controls.Clear ();
			table = CreateTable ();
			Controls.Add (table);
			headerRow = null;
			footerRow = null;
			topPagerRow = null;
			bottomPagerRow = null;
			ArrayList list = new ArrayList ();

			// Gets the current data item

			if (AllowPaging) {
				PageCount = pagedDataSource.DataSourceCount;
				if (PageIndex >= PageCount && PageCount > 0)
					pageIndex = pagedDataSource.CurrentPageIndex = PageCount - 1;
				if (pagedDataSource.DataSource != null) {
					IEnumerator e = pagedDataSource.GetEnumerator ();
					if (e.MoveNext ())
						dataItem = e.Current;
				}
			} else {
				int page = 0;
				object lastItem = null;
				if (pagedDataSource.DataSource != null) {
					IEnumerator e = pagedDataSource.GetEnumerator ();
					for (; e.MoveNext (); page++) {
						lastItem = e.Current;
						if (page == PageIndex)
							dataItem = e.Current;
					}
				}
				PageCount = page;
				if (PageIndex >= PageCount && PageCount > 0) {
					pageIndex = PageCount - 1;
					dataItem = lastItem;
				}
			}

			if (PageCount == 0 && CurrentMode != DetailsViewMode.Insert) {
				DetailsViewRow row = CreateEmptyRow ();
				if (row != null) {
					table.Rows.Add (row);
					list.Add (row);
				}
			} else {
				// Creates the set of fields to show

				ICollection fieldCollection = CreateFieldSet (dataItem, dataBinding && dataItem != null);
				DataControlField [] fields = new DataControlField [fieldCollection.Count];
				fieldCollection.CopyTo (fields, 0);

				foreach (DataControlField field in fields) {
					field.Initialize (false, this);
					if (EnablePagingCallbacks)
						field.ValidateSupportsCallback ();
				}

				// Main table creation

				headerRow = CreateRow (-1, DataControlRowType.Header, DataControlRowState.Normal);
				DataControlFieldCell headerCell = new DataControlFieldCell (null);
				headerCell.ColumnSpan = 2;
				if (headerTemplate != null)
					headerTemplate.InstantiateIn (headerCell);
				else if (!String.IsNullOrEmpty (HeaderText))
					headerCell.Text = HeaderText;
				else
					headerRow.Visible = false;
				headerRow.Cells.Add (headerCell);
				table.Rows.Add (headerRow);

				if (showPager && PagerSettings.Position == PagerPosition.Top ||
						PagerSettings.Position == PagerPosition.TopAndBottom) {
					topPagerRow = CreateRow (-1, DataControlRowType.Pager, DataControlRowState.Normal);
					InitializePager (topPagerRow, pagedDataSource);
					table.Rows.Add (topPagerRow);
				}

				foreach (DataControlField field in fields) {
					DataControlRowState rstate = GetRowState (list.Count);
					DetailsViewRow row = CreateRow (PageIndex, DataControlRowType.DataRow, rstate);
					InitializeRow (row, field);
					table.Rows.Add (row);
					list.Add (row);
				}

				footerRow = CreateRow (-1, DataControlRowType.Footer, DataControlRowState.Normal);
				DataControlFieldCell footerCell = new DataControlFieldCell (null);
				footerCell.ColumnSpan = 2;
				if (footerTemplate != null)
					footerTemplate.InstantiateIn (footerCell);
				else if (!String.IsNullOrEmpty (FooterText))
					footerCell.Text = FooterText;
				else
					footerRow.Visible = false;
				footerRow.Cells.Add (footerCell);
				table.Rows.Add (footerRow);

				if (showPager && PagerSettings.Position == PagerPosition.Bottom ||
						PagerSettings.Position == PagerPosition.TopAndBottom) {
					bottomPagerRow = CreateRow (-1, DataControlRowType.Pager, DataControlRowState.Normal);
					InitializePager (bottomPagerRow, pagedDataSource);
					table.Rows.Add (bottomPagerRow);
				}
			}
			
			rows = new DetailsViewRowCollection (list);

			if (dataBinding)
				DataBind (false);
			
			OnItemCreated (EventArgs.Empty);

			return PageCount;
		}

		protected override void EnsureDataBound ()
		{
			if (CurrentMode == DetailsViewMode.Insert) {
				if (RequiresDataBinding) {
					OnDataBinding (EventArgs.Empty);
					RequiresDataBinding = false;
					InternalPerformDataBinding (null);
					MarkAsDataBound ();
					OnDataBound (EventArgs.Empty);
				}
			} else
				base.EnsureDataBound ();
		}
		
		DataControlRowState GetRowState (int index)
		{
			DataControlRowState rstate = (index % 2) == 0 ? DataControlRowState.Normal : DataControlRowState.Alternate;
			if (CurrentMode == DetailsViewMode.Edit)
				rstate |= DataControlRowState.Edit;
			else if (CurrentMode == DetailsViewMode.Insert)
				rstate |= DataControlRowState.Insert;
			return rstate;
		}
		
		protected virtual void InitializePager (DetailsViewRow row, PagedDataSource pagedDataSource)
		{
			TableCell cell = new TableCell ();
			cell.ColumnSpan = 2;
			
			if (pagerTemplate != null)
				pagerTemplate.InstantiateIn (cell);
			else
				cell.Controls.Add (PagerSettings.CreatePagerControl (pagedDataSource.CurrentPageIndex, pagedDataSource.PageCount));
			
			row.Cells.Add (cell);
		}
		
		DetailsViewRow CreateEmptyRow ()
		{
			TableCell cell = new TableCell ();

			if (emptyDataTemplate != null)
				emptyDataTemplate.InstantiateIn (cell);
			else if (!String.IsNullOrEmpty (EmptyDataText))
				cell.Text = EmptyDataText;
			else
				return null;
			
			DetailsViewRow row = CreateRow (-1, DataControlRowType.EmptyDataRow, DataControlRowState.Normal);
			row.Cells.Add (cell);
			return row;
		}
		
		protected virtual void InitializeRow (DetailsViewRow row, DataControlField field)
		{
			if (!field.Visible) {
				row.Visible = false;
				return;
			}
			
			row.ContainingField = field;
			DataControlFieldCell cell;
			
			if (field.ShowHeader) {
				cell = new DataControlFieldCell (field);
				row.Cells.Add (cell);
				field.InitializeCell (cell, DataControlCellType.Header, row.RowState, row.RowIndex);
			}
			
			cell = new DataControlFieldCell (field);
			if (!field.ShowHeader)
				cell.ColumnSpan = 2;
			row.Cells.Add (cell);
			field.InitializeCell (cell, DataControlCellType.DataCell, row.RowState, row.RowIndex);

			if (CurrentMode == DetailsViewMode.Insert && !field.InsertVisible)
				row.Visible = false;
		}
		
		void FillRowDataKey (object dataItem)
		{
			KeyTable.Clear ();

			if (cachedKeyProperties == null) {
				PropertyDescriptorCollection props = TypeDescriptor.GetProperties (dataItem);
				cachedKeyProperties = new PropertyDescriptor [DataKeyNames.Length];
				for (int n=0; n<DataKeyNames.Length; n++) { 
					PropertyDescriptor p = props.Find (DataKeyNames [n], true);
					if (p == null)
						throw new InvalidOperationException ("Property '" + DataKeyNames[n] + "' not found in object of type " + dataItem.GetType());
					cachedKeyProperties [n] = p;
				}
			}
			
			foreach (PropertyDescriptor p in cachedKeyProperties)
				KeyTable [p.Name] = p.GetValue (dataItem);
		}
		
		IOrderedDictionary GetRowValues (bool includeReadOnlyFields, bool includePrimaryKey)
		{
			OrderedDictionary dic = new OrderedDictionary ();
			ExtractRowValues (dic, includeReadOnlyFields, includePrimaryKey);
			return dic;
		}
		
		protected virtual void ExtractRowValues (IOrderedDictionary fieldValues, bool includeReadOnlyFields, bool includeKeys)
		{
			foreach (DetailsViewRow row in Rows) {
				if (row.Cells.Count < 1)
					continue;
				DataControlFieldCell c = row.Cells[row.Cells.Count-1] as DataControlFieldCell;
				if (c != null)
					c.ContainingField.ExtractValuesFromCell (fieldValues, c, row.RowState, includeReadOnlyFields);
			}
			if (!includeKeys && DataKeyNames != null)
				foreach (string key in DataKeyNames)
					fieldValues.Remove (key);
		}
		
		protected override HtmlTextWriterTag TagKey {
			get {
				if (EnablePagingCallbacks)
					return HtmlTextWriterTag.Div;
				else
					return HtmlTextWriterTag.Table;
			}
		}
		
		public sealed override void DataBind ()
		{
			cachedKeyProperties = null;
			base.DataBind ();
			
			if (dataItem != null) {
				if (CurrentMode == DetailsViewMode.Edit)
					oldEditValues = new DataKey (GetRowValues (false, true));
				FillRowDataKey (dataItem);
				key = new DataKey (KeyTable);
			}
		}
		
		protected internal override void PerformDataBinding (IEnumerable data)
		{
			base.PerformDataBinding (data);
		}

		protected internal virtual void PrepareControlHierarchy ()
		{
			if (table == null)
				return;

			table.Caption = Caption;
			table.CaptionAlign = CaptionAlign;

			foreach (DetailsViewRow row in table.Rows) {
				switch (row.RowType) {
					case DataControlRowType.Header:
						if (headerStyle != null && !headerStyle.IsEmpty)
							row.ControlStyle.CopyFrom (headerStyle);
						break;
					case DataControlRowType.Footer:
						if (footerStyle != null && !footerStyle.IsEmpty)
							row.ControlStyle.CopyFrom (footerStyle);
						break;
					case DataControlRowType.Pager:
						if (pagerStyle != null && !pagerStyle.IsEmpty)
							row.ControlStyle.CopyFrom (pagerStyle);
						break;
					case DataControlRowType.EmptyDataRow:
						if (emptyDataRowStyle != null && !emptyDataRowStyle.IsEmpty)
							row.ControlStyle.CopyFrom (emptyDataRowStyle);
						break;
					case DataControlRowType.DataRow:
						if (rowStyle != null && !rowStyle.IsEmpty)
							row.ControlStyle.CopyFrom (rowStyle);
						if ((row.RowState & DataControlRowState.Alternate) != 0 && alternatingRowStyle != null && !alternatingRowStyle.IsEmpty)
							row.ControlStyle.CopyFrom (alternatingRowStyle);
						break;
					default:
						break;
				}

				if (row.ContainingField is CommandField) {
					if (commandRowStyle != null && !commandRowStyle.IsEmpty)
						row.ControlStyle.CopyFrom (commandRowStyle);
				} else {
					if ((row.RowState & DataControlRowState.Edit) != 0 && editRowStyle != null && !editRowStyle.IsEmpty)
						row.ControlStyle.CopyFrom (editRowStyle);
					if ((row.RowState & DataControlRowState.Insert) != 0) {
						if (insertRowStyle != null && !insertRowStyle.IsEmpty)
							row.ControlStyle.CopyFrom (insertRowStyle);
						else if (editRowStyle != null && !editRowStyle.IsEmpty)
							row.ControlStyle.CopyFrom (editRowStyle);
					}
				}

				for (int n = 0; n < row.Cells.Count; n++) {
					DataControlFieldCell fcell = row.Cells [n] as DataControlFieldCell;
					if (fcell != null && fcell.ContainingField != null) {
						DataControlField field = fcell.ContainingField;
						if (n == 0 && field.ShowHeader) {
							if (fieldHeaderStyle != null && !fieldHeaderStyle.IsEmpty)
								fcell.ControlStyle.CopyFrom (fieldHeaderStyle);
							if (field.HeaderStyleCreated && !field.HeaderStyle.IsEmpty)
								fcell.ControlStyle.CopyFrom (field.HeaderStyle);
						} else {
							if (field.ControlStyleCreated && !field.ControlStyle.IsEmpty) {
								foreach (Control c in fcell.Controls) {
									WebControl wc = c as WebControl;
									if (wc != null)
										wc.ControlStyle.MergeWith (field.ControlStyle);
								}
							}
							
							if (field.ItemStyleCreated && !field.ItemStyle.IsEmpty)
								fcell.ControlStyle.CopyFrom (field.ItemStyle);
						}
					}
				}
			}
		}
		
		protected internal override void OnInit (EventArgs e)
		{
			Page page = Page;
			if (page != null)
				page.RegisterRequiresControlState (this);
			base.OnInit (e);
		}
		
		void OnFieldsChanged (object sender, EventArgs args)
		{
			RequireBinding ();
		}
		
		protected override void OnDataSourceViewChanged (object sender, EventArgs e)
		{
			base.OnDataSourceViewChanged (sender, e);
			RequireBinding ();
		}
		
		protected override bool OnBubbleEvent (object source, EventArgs e)
		{
			DetailsViewCommandEventArgs args = e as DetailsViewCommandEventArgs;
			if (args != null) {
				bool causesValidation = false;
				IButtonControl button = args.CommandSource as IButtonControl;
				if (button != null && button.CausesValidation) {
					Page.Validate (button.ValidationGroup);
					causesValidation = true;
				}
				ProcessCommand (args, causesValidation);
				return true;
			}
			return base.OnBubbleEvent (source, e);
		}

		void ProcessCommand (DetailsViewCommandEventArgs args, bool causesValidation) {
			OnItemCommand (args);
			ProcessEvent (args.CommandName, args.CommandArgument as string, causesValidation);
		}

		void IPostBackEventHandler.RaisePostBackEvent (string eventArgument)
		{
			RaisePostBackEvent (eventArgument);
		}

		// TODO: This is prolly obsolete
		protected virtual void RaisePostBackEvent (string eventArgument)
		{
			ValidateEvent (UniqueID, eventArgument);
			int i = eventArgument.IndexOf ('$');
			CommandEventArgs arg;
			if (i != -1)
				arg = new CommandEventArgs (eventArgument.Substring (0, i), eventArgument.Substring (i + 1));
			else
				arg = new CommandEventArgs (eventArgument, null);
			ProcessCommand (new DetailsViewCommandEventArgs (this, arg), false);
		}

		void ProcessEvent (string eventName, string param, bool causesValidation)
		{
			switch (eventName) {
				case DataControlCommands.PageCommandName:
					int newIndex = -1;
					switch (param) {
						case DataControlCommands.FirstPageCommandArgument:
							newIndex = 0;
							break;
						case DataControlCommands.LastPageCommandArgument:
							newIndex = PageCount - 1;
							break;
						case DataControlCommands.NextPageCommandArgument:
							newIndex = PageIndex + 1;
							break;
						case DataControlCommands.PreviousPageCommandArgument:
							newIndex = PageIndex - 1;
							break;
						default:
							int paramIndex = 0;
							int.TryParse (param, out paramIndex);
							newIndex = paramIndex - 1;
							break;
					}
					SetPageIndex (newIndex);
					break;
					
				case DataControlCommands.FirstPageCommandArgument:
					SetPageIndex (0);
					break;

				case DataControlCommands.LastPageCommandArgument:
					SetPageIndex (PageCount - 1);
					break;
					
				case DataControlCommands.NextPageCommandArgument:
					if (PageIndex < PageCount - 1)
						SetPageIndex (PageIndex + 1);
					break;

				case DataControlCommands.PreviousPageCommandArgument:
					if (PageIndex > 0)
						SetPageIndex (PageIndex - 1);
					break;
					
				case DataControlCommands.EditCommandName:
					ProcessChangeMode (DetailsViewMode.Edit);
					break;
					
				case DataControlCommands.NewCommandName:
					ProcessChangeMode (DetailsViewMode.Insert);
					break;
					
				case DataControlCommands.UpdateCommandName:
					UpdateItem (param, causesValidation);
					break;
					
				case DataControlCommands.CancelCommandName:
					CancelEdit ();
					break;
					
				case DataControlCommands.DeleteCommandName:
					DeleteItem ();
					break;
					
				case DataControlCommands.InsertCommandName:
					InsertItem (causesValidation);
					break;
			}
		}
		public
		void SetPageIndex (int index)
		{
			DetailsViewPageEventArgs args = new DetailsViewPageEventArgs (index);
			OnPageIndexChanging (args);

			if (args.Cancel || !IsBoundUsingDataSourceID)
				return;
			
			if (args.NewPageIndex < 0 || args.NewPageIndex >= PageCount)
				return;
			EndRowEdit (false);
			PageIndex = args.NewPageIndex;
			OnPageIndexChanged (EventArgs.Empty);
		}
		
		public void ChangeMode (DetailsViewMode newMode)
		{
			CurrentMode = newMode;
			RequireBinding ();
		}

		void ProcessChangeMode (DetailsViewMode newMode)
		{
			DetailsViewModeEventArgs args = new DetailsViewModeEventArgs (newMode, false);
			OnModeChanging (args);

			if (args.Cancel || !IsBoundUsingDataSourceID)
				return;

			ChangeMode (args.NewMode);

			OnModeChanged (EventArgs.Empty);
		}

		void CancelEdit ()
		{
			DetailsViewModeEventArgs args = new DetailsViewModeEventArgs (DetailsViewMode.ReadOnly, true);
			OnModeChanging (args);

			if (args.Cancel || !IsBoundUsingDataSourceID)
				return;

			EndRowEdit ();
		}

		public virtual void UpdateItem (bool causesValidation)
		{
			UpdateItem (null, causesValidation);
		}
		
		void UpdateItem (string param, bool causesValidation)
		{
			if (causesValidation && Page != null && !Page.IsValid)
				return;
			
			if (CurrentMode != DetailsViewMode.Edit)
				throw new HttpException ();

			currentEditOldValues = OldEditValues.Values;

			currentEditRowKeys = DataKey.Values;
			currentEditNewValues = GetRowValues (false, false);
			
			DetailsViewUpdateEventArgs args = new DetailsViewUpdateEventArgs (param, currentEditRowKeys, currentEditOldValues, currentEditNewValues);
			OnItemUpdating (args);

			if (args.Cancel || !IsBoundUsingDataSourceID)
				return;
			
			DataSourceView view = GetData ();
			if (view == null)
				throw new HttpException ("The DataSourceView associated to data bound control was null");
			view.Update (currentEditRowKeys, currentEditNewValues, currentEditOldValues, new DataSourceViewOperationCallback (UpdateCallback));
		}

		bool UpdateCallback (int recordsAffected, Exception exception)
		{
			DetailsViewUpdatedEventArgs dargs = new DetailsViewUpdatedEventArgs (recordsAffected, exception, currentEditRowKeys, currentEditOldValues, currentEditNewValues);
			OnItemUpdated (dargs);

			if (!dargs.KeepInEditMode)				
				EndRowEdit ();

			return dargs.ExceptionHandled;
		}

		public virtual void InsertItem (bool causesValidation)
		{
			InsertItem (null, causesValidation);
		}
		
		void InsertItem (string param, bool causesValidation)
		{
			if (causesValidation && Page != null && !Page.IsValid)
				return;
			
			if (CurrentMode != DetailsViewMode.Insert)
				throw new HttpException ();
			
			currentEditNewValues = GetRowValues (false, true);
			DetailsViewInsertEventArgs args = new DetailsViewInsertEventArgs (param, currentEditNewValues);
			OnItemInserting (args);

			if (args.Cancel || !IsBoundUsingDataSourceID)
				return;

			DataSourceView view = GetData ();
			if (view == null)
				throw new HttpException ("The DataSourceView associated to data bound control was null");
			view.Insert (currentEditNewValues, new DataSourceViewOperationCallback (InsertCallback));
		}
		
		bool InsertCallback (int recordsAffected, Exception exception)
		{
			DetailsViewInsertedEventArgs dargs = new DetailsViewInsertedEventArgs (recordsAffected, exception, currentEditNewValues);
			OnItemInserted (dargs);

			if (!dargs.KeepInInsertMode)				
				EndRowEdit ();

			return dargs.ExceptionHandled;
		}

		public virtual void DeleteItem ()
		{
			currentEditRowKeys = DataKey.Values;
			currentEditNewValues = GetRowValues (true, false);
			
			DetailsViewDeleteEventArgs args = new DetailsViewDeleteEventArgs (PageIndex, currentEditRowKeys, currentEditNewValues);
			OnItemDeleting (args);

			if (args.Cancel || !IsBoundUsingDataSourceID)
				return;

			DataSourceView view = GetData ();
			if (view != null)
				view.Delete (currentEditRowKeys, currentEditNewValues, new DataSourceViewOperationCallback (DeleteCallback));
			else {
				DetailsViewDeletedEventArgs dargs = new DetailsViewDeletedEventArgs (0, null, currentEditRowKeys, currentEditNewValues);
				OnItemDeleted (dargs);
			}
			if (PageIndex > 0 && PageIndex == PageCount - 1)
				PageIndex --;
			RequireBinding ();
		}

		bool DeleteCallback (int recordsAffected, Exception exception)
		{
			DetailsViewDeletedEventArgs dargs = new DetailsViewDeletedEventArgs (recordsAffected, exception, currentEditRowKeys, currentEditNewValues);
			OnItemDeleted (dargs);
			return dargs.ExceptionHandled;
		}
		
		void EndRowEdit ()
		{
			EndRowEdit (true);
		}

		void EndRowEdit (bool switchToDefaultMode)
		{
			if (switchToDefaultMode)
				ChangeMode (DefaultMode);
			oldEditValues = new DataKey (new OrderedDictionary ());
			currentEditRowKeys = null;
			currentEditOldValues = null;
			currentEditNewValues = null;
			RequireBinding ();
		}

		protected internal override void LoadControlState (object savedState)
		{
			if (savedState == null)
				return;
			object[] state = (object[]) savedState;
			base.LoadControlState (state[0]);
			pageIndex = (int) state[1];
			pageCount = (int) state[2];
			CurrentMode = (DetailsViewMode) state[3];
			dataKeyNames = (string[]) state[4];
			defaultMode = (DetailsViewMode) state[5];
			if (state [6] != null)
				((IStateManager) DataKey).LoadViewState (state [6]);
			if (state [7] != null)
				((IStateManager) OldEditValues).LoadViewState (state [7]);
		}
		
		protected internal override object SaveControlState ()
		{
			object bstate = base.SaveControlState ();
			return new object[] {
				bstate, 
				pageIndex, 
				pageCount, 
				CurrentMode, 
				dataKeyNames, 
				defaultMode,
				(key == null ? null : ((IStateManager)key).SaveViewState()),
				(oldEditValues == null ? null : ((IStateManager) oldEditValues).SaveViewState ())
			};
		}
		
		protected override void TrackViewState()
		{
			base.TrackViewState();
			if (columns != null)
				((IStateManager)columns).TrackViewState();
			if (pagerSettings != null)
				((IStateManager)pagerSettings).TrackViewState();
			if (alternatingRowStyle != null)
				((IStateManager)alternatingRowStyle).TrackViewState();
			if (footerStyle != null)
				((IStateManager)footerStyle).TrackViewState();
			if (headerStyle != null)
				((IStateManager)headerStyle).TrackViewState();
			if (pagerStyle != null)
				((IStateManager)pagerStyle).TrackViewState();
			if (rowStyle != null)
				((IStateManager)rowStyle).TrackViewState();
			if (editRowStyle != null)
				((IStateManager)editRowStyle).TrackViewState();
			if (insertRowStyle != null)
				((IStateManager)insertRowStyle).TrackViewState();
			if (emptyDataRowStyle != null)
				((IStateManager)emptyDataRowStyle).TrackViewState();
			if (key != null)
				((IStateManager)key).TrackViewState();
			if (autoFieldProperties != null) {
				foreach (IStateManager sm in autoFieldProperties)
					sm.TrackViewState ();
			}
			if (ControlStyleCreated)
				ControlStyle.TrackViewState ();
		}

		protected override object SaveViewState()
		{
			object[] states = new object [13];
			states[0] = base.SaveViewState();
			states[1] = (columns == null ? null : ((IStateManager)columns).SaveViewState());
			states[2] = (pagerSettings == null ? null : ((IStateManager)pagerSettings).SaveViewState());
			states[3] = (alternatingRowStyle == null ? null : ((IStateManager)alternatingRowStyle).SaveViewState());
			states[4] = (footerStyle == null ? null : ((IStateManager)footerStyle).SaveViewState());
			states[5] = (headerStyle == null ? null : ((IStateManager)headerStyle).SaveViewState());
			states[6] = (pagerStyle == null ? null : ((IStateManager)pagerStyle).SaveViewState());
			states[7] = (rowStyle == null ? null : ((IStateManager)rowStyle).SaveViewState());
			states[8] = (insertRowStyle == null ? null : ((IStateManager)insertRowStyle).SaveViewState());
			states[9] = (editRowStyle == null ? null : ((IStateManager)editRowStyle).SaveViewState());
			states[10] = (emptyDataRowStyle == null ? null : ((IStateManager)emptyDataRowStyle).SaveViewState());
			
			if (autoFieldProperties != null) {
				object[] data = new object [autoFieldProperties.Length];
				bool allNull = true;
				for (int n=0; n<data.Length; n++) {
					data [n] = ((IStateManager)autoFieldProperties [n]).SaveViewState ();
					if (data [n] != null) allNull = false;
				}
				if (!allNull) states [11] = data;
			}
			if (ControlStyleCreated)
				states [12] = ControlStyle.SaveViewState ();

			for (int i = states.Length - 1; i >= 0; i--) {
				if (states [i] != null)
					return states;
			}

			return null;
		}

		protected override void LoadViewState (object savedState)
		{
			if (savedState == null) {
				base.LoadViewState (null);
				return;
			}

			object [] states = (object []) savedState;
			
			if (states[11] != null) {
				object[] data = (object[]) states [11];
				autoFieldProperties = new AutoGeneratedFieldProperties [data.Length];
				for (int n=0; n<data.Length; n++) {
					IStateManager p = new AutoGeneratedFieldProperties ();
					p.TrackViewState ();
					p.LoadViewState (data [n]);
					autoFieldProperties [n] = (AutoGeneratedFieldProperties) p;
				}
			}

			base.LoadViewState (states[0]);
			
			if (states[1] != null) ((IStateManager)Fields).LoadViewState (states[1]);
			if (states[2] != null) ((IStateManager)PagerSettings).LoadViewState (states[2]);
			if (states[3] != null) ((IStateManager)AlternatingRowStyle).LoadViewState (states[3]);
			if (states[4] != null) ((IStateManager)FooterStyle).LoadViewState (states[4]);
			if (states[5] != null) ((IStateManager)HeaderStyle).LoadViewState (states[5]);
			if (states[6] != null) ((IStateManager)PagerStyle).LoadViewState (states[6]);
			if (states[7] != null) ((IStateManager)RowStyle).LoadViewState (states[7]);
			if (states[8] != null) ((IStateManager)InsertRowStyle).LoadViewState (states[8]);
			if (states[9] != null) ((IStateManager)EditRowStyle).LoadViewState (states[9]);
			if (states[10] != null) ((IStateManager)EmptyDataRowStyle).LoadViewState (states[10]);
			if (states [12] != null)
				ControlStyle.LoadViewState (states [12]);
		}
		
		void ICallbackEventHandler.RaiseCallbackEvent (string eventArgument)
		{
			RaiseCallbackEvent (eventArgument);
		}
		
		protected virtual void RaiseCallbackEvent (string eventArgument)
		{
			string[] clientData = eventArgument.Split ('|');
			PageIndex = int.Parse (clientData[0]);
			
			RaisePostBackEvent (clientData[1]);
			DataBind ();
		}

		string ICallbackEventHandler.GetCallbackResult ()
		{
			return GetCallbackResult ();
		}

		protected virtual string GetCallbackResult ()
		{
			PrepareControlHierarchy ();

			StringWriter sw = new StringWriter ();
			sw.Write (PageIndex.ToString () + '|');

			HtmlTextWriter writer = new HtmlTextWriter (sw);
			RenderGrid (writer);
			return sw.ToString ();
		}

		protected virtual string GetCallbackScript (IButtonControl buttonControl, string argument)
		{
			if (EnablePagingCallbacks) {
				Page page = Page;
				if (page != null)
					page.ClientScript.RegisterForEventValidation (UniqueID, argument);
				return "javascript:DetailsView_ClientEvent (\"" + ClientID + "\",\"" + buttonControl.CommandName + "$" + buttonControl.CommandArgument + "\"); return false;";
			} else
				return null;
		}
		
		string ICallbackContainer.GetCallbackScript (IButtonControl control, string argument)
		{
			return GetCallbackScript (control, argument);
		}

		protected override void OnPagePreLoad (object sender, EventArgs e)
		{
			base.OnPagePreLoad (sender, e);

			if (Page.IsPostBack && EnablePagingCallbacks) {
				int page;
				if (int.TryParse (Page.Request.Form [ClientID + "_Page"], out page))
					PageIndex = page;
			}
		}

		const string onPreRenderScript = @"var {0} = new Object ();
{0}.pageIndex = {1};
{0}.uid = {2};
{0}.form = {3};
";
		protected internal override void OnPreRender (EventArgs e)
		{
			base.OnPreRender (e);

			Page page = Page;
			if (EnablePagingCallbacks && page != null) {
				ClientScriptManager scriptManager = page.ClientScript;
				if (!scriptManager.IsClientScriptIncludeRegistered (typeof(DetailsView), "DetailsView.js")) {
					string url = scriptManager.GetWebResourceUrl (typeof(DetailsView), "DetailsView.js");
					scriptManager.RegisterClientScriptInclude (typeof(DetailsView), "DetailsView.js", url);
				}
				scriptManager.RegisterHiddenField (ClientID + "_Page", PageIndex.ToString ());
				
				string cgrid = ClientID + "_data";
				string script = String.Format (onPreRenderScript,
							       cgrid,
							       ClientScriptManager.GetScriptLiteral (PageIndex),
							       ClientScriptManager.GetScriptLiteral (UniqueID),
							       page.theForm);
				
				scriptManager.RegisterStartupScript (typeof(TreeView), this.UniqueID, script, true);
				
				// Make sure the basic script infrastructure is rendered
				scriptManager.GetCallbackEventReference (this, "null", String.Empty, "null");
				scriptManager.GetPostBackClientHyperlink (this, String.Empty, true);
			}
		}
		
		protected internal override void Render (HtmlTextWriter writer)
		{
			PrepareControlHierarchy ();

			if (EnablePagingCallbacks)
				writer.AddAttribute (HtmlTextWriterAttribute.Id, ClientID + "_div");
			writer.RenderBeginTag (HtmlTextWriterTag.Div);

			RenderGrid (writer);

			writer.RenderEndTag ();
		}
		
		void RenderGrid (HtmlTextWriter writer)
		{
			if (table == null)
				return;

			table.Render (writer);
		}

		PostBackOptions IPostBackContainer.GetPostBackOptions (IButtonControl control)
		{
			if (control == null)
				throw new ArgumentNullException ("control");

			if (control.CausesValidation)
				throw new InvalidOperationException ("A button that causes validation in DetailsView '" + ID + "' is attempting to use the container GridView as the post back target.  The button should either turn off validation or use itself as the post back container.");

			PostBackOptions options = new PostBackOptions (this);
			options.Argument = control.CommandName + "$" + control.CommandArgument;
			options.RequiresJavaScriptProtocol = true;

			return options;
		}
	}
}
